#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "MQTTClient.h"
#include <stdlib.h>
#include "cJSON.h"
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <assert.h>
#include "msg_queue_peer.h"
#include "shmem.h"
#include <signal.h>
#include <pthread.h>
#include <sys/mman.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <errno.h>
#include <sys/sem.h>
#include <sys/wait.h>
#include <time.h>
#include <sys/time.h>
#include <sys/select.h>
#include <sys/msg.h>
#include <sqlite3.h>

static struct shm_param para;

union val_t
{
    int b_val;   // bool类型存储空间
    int i_val;   // 整形值存储空间
    float f_val; // 浮点值存储空间
};
struct std_node
{
    int key;             // 唯一键值
    int type;            // 数据点类型
    int dev_type;        // 数据点属于哪个设备，根据网关支持的设备自行定义
    union val_t old_val; // 变化上报后需要更新旧值
    union val_t new_val; // 从共享内存取出最新数据，放到new_val中
    int ret;             // 默认为-1，采集成功后设置为0，采集失败再置-1
};

struct msgbuf
{
    long mtype;
    int key;
    char mdata[256];
};

struct msgbuf_mode
{
    long mtype;
    int mode;
    int N_key;
    int P_key;
    double N_val;
    double P_val;
};

char IP[256] = {0};
char PORT[256] = {0};
double Past = 0;
static int *total;                       // 指向共享内存中数据节点总个数
static struct std_node *node_arr = NULL; // 指向共享内存中节点缓存数组头

#define MAX_NODE 128 // 最大支持学生数目
#define STD_NODE_LEN sizeof(struct student)
#define MAX_NODE_SIZE (MAX_NODE * STD_NODE_LEN)

// 定义MQTT服务器的地址
// #define ADDRESS "tcp://192.168.51.187:1883"
// 定义客户端ID
#define CLIENTID "ExampleClientSub"
// 定义订阅和发布的主题
#define TOPIC_UP "/app/data/up"
#define TOPIC_UP_LS "/app/history"
#define TOPIC_DOWN "/app/control/down"
// 定义默认的消息内容
#define PAYLOAD "Hello World!"
// 定义服务质量等级
#define QOS 1
// 定义操作超时时间
#define TIMEOUT 10000L

// 定义MQTT客户端句柄
MQTTClient client;

// 用于存储接收到的Qt客户端消息内容
char *qt_msg = NULL;

// 用于存储接收到的共享内存内容的指针
char input[2048];

// 用于存储接收到的消息内容的指针
char *payloadptr = NULL;

// 用于存储接收到的消息内容的指针
volatile MQTTClient_deliveryToken deliveredtoken;
// 用于存储上报模式 mode=0 表示定时上报 mode=1 表示刷新上报 mode=2 表示变化上报
volatile int mode = 0;

// 上报模式type
cJSON *type_data = NULL;

cJSON *type = NULL;

// 历史数据上报
cJSON *status = NULL;

// 用于存储消息发送确认的令牌
volatile MQTTClient_deliveryToken deliveredtoken;

// 定义一个标志位，用来判断new_val和old_val是否相等0表示相等，1表示不相等
int flag = 0;

// 定义IP
char ADDRESS[256] = "tcp://";

// 定义数据库文件路径
sqlite3 *db;
char *errmsg;

int t = 0;

int mode_zd = 0;

/**
 * @brief 消息发送确认回调函数
 * 当消息成功发送到MQTT服务器并得到确认时，会调用此函数。
 * @param context 上下文指针，可用于传递额外的数据，这里未使用
 * @param dt 消息发送确认的令牌，用于标识该消息
 */
void delivered(void *context, MQTTClient_deliveryToken dt)
{
    // 打印消息发送确认信息，包含令牌值
    printf("消息已确认发送，令牌值为 %d\n", dt);
    // 将令牌值保存到全局变量中
    deliveredtoken = dt;
}

void getdata()
{
    // 获取当前时间戳
    time_t t = time(NULL);
    // 创建一个JSON对象
    cJSON *json = cJSON_CreateObject();
    // 添加type节点
    cJSON_AddNumberToObject(json, "type", 4);
    // 添加data数组
    cJSON *data_array = cJSON_CreateArray();
    cJSON_AddItemToObject(json, "data", data_array);
    // data数组中添加两个节点
    cJSON *node1 = cJSON_CreateObject();
    cJSON_AddNumberToObject(node1, "key", node_arr[0].key);

    char str[20]; // 足够存储转换后的字符串
    // 使用 sprintf 函数
    sprintf(str, "%.2lf", node_arr[0].new_val.f_val);
    // 添加value节点
    cJSON_AddItemToObject(node1, "value", cJSON_CreateString(str));

    cJSON_AddNumberToObject(node1, "timestamp", t);
    cJSON_AddItemToArray(data_array, node1);
    cJSON *node2 = cJSON_CreateObject();
    cJSON_AddNumberToObject(node2, "key", node_arr[1].key);

    char str1[20]; // 足够存储转换后的字符串
    // 使用 sprintf 函数
    sprintf(str1, "%.2lf", node_arr[1].new_val.f_val);
    // 添加value节点
    cJSON_AddItemToObject(node2, "value", cJSON_CreateString(str1));

    cJSON_AddNumberToObject(node2, "timestamp", t);
    cJSON_AddItemToArray(data_array, node2);
    // 将JSON对象转换为字符串
    char *out = cJSON_Print(json);
    printf("out = %s\n", out);
    // 将时间戳和out字符串放到sqlite数据库中的data表中
    char sql[256] = {};
    sprintf(sql, "INSERT INTO data (timestamp, data) VALUES (%ld, '%s')", t, out);
    int rc = sqlite3_exec(db, sql, NULL, NULL, &errmsg);
    if (rc != SQLITE_OK)
    {
        fprintf(stderr, "SQL error: %s\n", errmsg);
        sqlite3_free(errmsg);
    }
    // 释放JSON对象
    cJSON_Delete(json);
    // 释放字符串
    free(out);
}

void sendMessage(MQTTClient client, const char *payload)
{
    // 初始化消息结构体
    MQTTClient_message pubmsg = MQTTClient_message_initializer;
    // 设置消息的负载为传入的消息内容
    pubmsg.payload = (void *)payload;
    // 设置消息负载的长度
    pubmsg.payloadlen = strlen(payload);
    // 设置消息的服务质量等级
    pubmsg.qos = QOS;
    // 设置消息是否保留
    pubmsg.retained = 0;
    // 用于存储消息发布的令牌
    MQTTClient_deliveryToken token;
    int rc;

    // 发布消息到指定主题
    rc = MQTTClient_publishMessage(client, TOPIC_UP, &pubmsg, &token);
    if (rc != MQTTCLIENT_SUCCESS)
    {
        // 若发布失败，打印错误信息
        printf("消息发布失败，返回码 %d\n", rc);
    }
    else
    {
        // 若发布成功，打印等待消息发送完成的提示信息
        printf("正在等待最多 %d 秒以完成消息 %s 的发布\n"
               "主题为 %s，客户端ID为 %s\n",
               (int)(TIMEOUT / 10000), payload, TOPIC_UP, CLIENTID);
        // 等待消息发送完成
        rc = MQTTClient_waitForCompletion(client, token, TIMEOUT / 10000);
        // 打印消息发送完成的提示信息，包含令牌值
        printf("消息已发送，令牌值为 %d\n", token);
    }
}

void sendLs(MQTTClient client, const char *payload)
{
    // 初始化消息结构体
    MQTTClient_message pubmsg = MQTTClient_message_initializer;
    // 设置消息的负载为传入的消息内容
    pubmsg.payload = (void *)payload;
    // 设置消息负载的长度
    pubmsg.payloadlen = strlen(payload);
    // 设置消息的服务质量等级
    pubmsg.qos = QOS;
    // 设置消息是否保留
    pubmsg.retained = 0;
    // 用于存储消息发布的令牌
    MQTTClient_deliveryToken token;
    int rc;

    // 发布消息到指定主题
    rc = MQTTClient_publishMessage(client, TOPIC_UP_LS, &pubmsg, &token);
    if (rc != MQTTCLIENT_SUCCESS)
    {
        // 若发布失败，打印错误信息
        printf("消息发布失败，返回码 %d\n", rc);
    }
    else
    {
        // 若发布成功，打印等待消息发送完成的提示信息
        printf("正在等待最多 %d 秒以完成消息 %s 的发布\n"
               "主题为 %s，客户端ID为 %s\n",
               (int)(TIMEOUT / 10000), payload, TOPIC_UP_LS, CLIENTID);
        // 等待消息发送完成
        rc = MQTTClient_waitForCompletion(client, token, TIMEOUT / 10000);
        // 打印消息发送完成的提示信息，包含令牌值
        printf("消息已发送，令牌值为 %d\n", token);
    }
}

// 变化上报线程函数
void *change_thread(void *arg)
{
    sendMessage(client, input);
    getdata();
    while (1)
    {
        if (flag == 1)
        {
            // 调用sendMessage函数发送消息
            sendMessage(client, input);
            getdata();
            printf("flag = %d\n", flag);
            flag = 0;
        }
        if (type->valueint == 2)
        {
            if (type_data->valueint != 1)
            {
                break;
            }
            if (type->valueint != 3)
            {
                break;
            }
        }
        else if (type->valueint == 5)
        {
            if (mode_zd != 1)
            {
                break;
            }
        }
    }
    pthread_exit(NULL); // 线程退出
    return NULL;
}

// 定时上报线程函数
void *report_thread(void *arg)
{
    int time = *(int *)arg;
    free(arg); // 释放动态分配的内存

    while (1)
    {
        // 调用sendMessage函数发送消息
        sendMessage(client, input);
        getdata();
        // 等待指定的时间间隔
        sleep(time);
        if (type_data->valueint != 2)
        {
            break;
        }
        if (type->valueint != 3)
        {
            break;
        }
    }
    pthread_exit(NULL); // 线程退出
    return NULL;
}

// 历史数据查询线程函数
void *history_thread(void *arg)
{
    printf("初始时间 t = %d\n", t);

    // 打开数据库
    sqlite3 *db;
    int rc = sqlite3_open("gateWay.db", &db);
    if (rc != SQLITE_OK)
    {
        fprintf(stderr, "无法打开数据库: %s\n", sqlite3_errmsg(db));
        sqlite3_close(db);
        return NULL;
    }

    // 准备SQL查询，包含timestamp列以便获取时间值
    sqlite3_stmt *stmt;
    const char *sql = "SELECT data, timestamp FROM data WHERE timestamp > ? ORDER BY timestamp ASC LIMIT 1";
    rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
    if (rc != SQLITE_OK)
    {
        fprintf(stderr, "SQL准备失败: %s\n", sqlite3_errmsg(db));
        sqlite3_close(db);
        return NULL;
    }

    printf("status->valueint = %d\n", status->valueint);

    // 循环执行查询操作，每次提取一条记录并发送
    while (status->valueint == 1)
    {
        // 绑定时间参数（使用全局变量t）
        sqlite3_bind_int(stmt, 1, t);

        // 执行查询
        rc = sqlite3_step(stmt);
        if (rc == SQLITE_ROW)
        {
            // 获取data字段的值
            const char *data = (const char *)sqlite3_column_text(stmt, 0);

            // 获取timestamp字段的值（现在是第二列）
            const unsigned char *timestamp_str = sqlite3_column_text(stmt, 1);

            // 调用sendMessage函数发送消息
            sendLs(client, data);

            // 更新全局时间戳t为当前记录的值
            if (timestamp_str)
            {
                int new_time = atoi((const char *)timestamp_str);
                if (new_time > t)
                { // 确保时间戳是递增的
                    t = new_time;
                    printf("更新后的时间 t = %d\n", t);
                }
                else
                {
                    printf("警告: 数据库时间戳不大于当前值: %d\n", new_time);
                    t++; // 防止死循环，手动递增
                }
            }
            else
            {
                printf("警告: 无法获取时间戳值\n");
                t++; // 防止死循环，手动递增
            }

            // 重置语句以重新执行查询
            sqlite3_reset(stmt);
        }
        else if (rc == SQLITE_DONE)
        {
            // 没有更多记录，重置语句
            printf("没有找到更新的记录，等待...\n");
            break;
        }
        else
        {
            // 查询错误
            fprintf(stderr, "SQL执行错误: %s\n", sqlite3_errmsg(db));
            break;
        }

        // 等待指定的时间间隔
        sleep(1);
    }

    // 清理资源
    sqlite3_finalize(stmt);
    sqlite3_close(db);
    printf("历史线程退出\n");
    return NULL;
}

/**
 * @brief 消息到达回调函数
 * 当客户端接收到来自订阅主题的消息时，会调用此函数。
 * @param context 上下文指针，可用于传递额外的数据，这里未使用
 * @param topicName 收到消息的主题名称
 * @param topicLen 主题名称的长度
 * @param message 接收到的消息结构体，包含消息内容和相关信息
 * @return int 通常返回1表示处理成功
 */
int msgarrvd(void *context, char *topicName, int topicLen, MQTTClient_message *message)
{
    int i;

    // 打印消息到达提示
    printf("收到消息\n");
    // 打印消息来自的主题
    printf("     主题: %s\n", topicName);
    // 打印消息内容提示
    printf("   消息内容: ");

    // 获取消息内容的指针
    payloadptr = message->payload;
#if 0
    // 逐个字符打印消息内容
    for(i=0; i<message->payloadlen; i++)
    {
        putchar(*payloadptr++);
    }
#endif
    // 直接打印消息内容
    printf("接收到的消息 = %s\n", payloadptr);
    // 将接收到的消息保存到Qt.JSON文件中
    FILE *fp = fopen("Qt.JSON", "w");
    if (fp == NULL)
    {
        perror("fopen err");
    }
    fwrite(payloadptr, 1, message->payloadlen, fp);
    fclose(fp);

    if (payloadptr != NULL)
    { // 解析Qt_JSON数据
        cJSON *qt = cJSON_Parse(payloadptr);
        if (qt == NULL)
        {
            printf("cJSON_Parse err\n");
            return -1;
        }
        // 获取type的值
        type = cJSON_GetObjectItem(qt, "type");
        printf("type = %d\n", type->valueint);
        if (type == NULL)
        {
            printf("cJSON_GetObjectItem err\n");
            return -1;
        }
        else if (type->valueint == 1) // 刷新上报
        {
            sendMessage(client, input);
            getdata();
        }
        else if (type->valueint == 2) // 控制设备
        {
            // 获取data数组
            cJSON *data = cJSON_GetObjectItem(qt, "data");
            if (data == NULL)
            {
                printf("cJSON_GetObjectItem err\n");
                return -1;
            }
            printf("获取到data数组\n");
            // 获取数组data中msg的值
            cJSON *msg = cJSON_GetObjectItem(data, "msg");
            // 获取数组data中key的值
            cJSON *key = cJSON_GetObjectItem(data, "key");
            // 获取数组data中value的值
            cJSON *value = cJSON_GetObjectItem(data, "val");
            if (msg == NULL || key == NULL || value == NULL)
            {
                printf("cJSON_GetObjectItem err\n");
                return -1;
            }

            struct msgbuf send_buf;
            // 这个mtype可以不用，但是必须赋一个不小于0的数
            send_buf.mtype = msg->valueint;
            printf("send_buf.mtype = %ld\n", send_buf.mtype);
            send_buf.key = key->valueint;
            printf("send_buf.key = %d\n", send_buf.key);
            strcpy(send_buf.mdata, value->valuestring);
            printf("send_buf.mdata = %s\n", send_buf.mdata);

            if (msg_queue_send("topic", &send_buf, sizeof(send_buf), 0) < 0)
            {
                printf("msg_queue_send error\n");
                return -1;
            }
        }
        else if (type->valueint == 3) // 上报模式
        {
            // 获取data数组
            cJSON *data = cJSON_GetObjectItem(qt, "data");
            if (data == NULL)
            {
                printf("cJSON_GetObjectItem err\n");
                return -1;
            }
            // 获取数组data中type的值
            type_data = cJSON_GetObjectItem(data, "type");
            printf("type = %d\n", type_data->valueint);
            if (type_data == NULL)
            {
                printf("cJSON_GetObjectItem err\n");
                return -1;
            }
            // 根据type的值，更改上报模式
            if (type_data->valueint == 0) // 不上报
            {
            }
            else if (type_data->valueint == 1) // 变化上报
            {
                pthread_t tid;
                pthread_create(&tid, NULL, change_thread, NULL);
                // 设置线程为分离状态，避免内存泄漏
                pthread_detach(tid);
            }
            else if (type_data->valueint == 2) // 定时上报
            {
                pthread_t tid;
                // 获取data数组中period的值
                cJSON *period = cJSON_GetObjectItem(data, "period");

                // 动态分配内存存储时间值
                int *time_interval = malloc(sizeof(int));
                if (time_interval == NULL)
                {
                    printf("内存分配失败\n");
                    return -1;
                }
                *time_interval = period->valueint;

                // 传递指向时间值的指针
                pthread_create(&tid, NULL, report_thread, time_interval);
                // 设置线程为分离状态，避免内存泄漏
                pthread_detach(tid);
            }
        }
        else if (type->valueint == 4) // 历史数据
        {
            // 获取time节点
            cJSON *time = cJSON_GetObjectItem(qt, "time");
            if (time == NULL)
            {
                printf("cJSON_GetObjectItem err\n");
                return -1;
            }
            // 获取time节点的值
            t = time->valueint;
            printf("t = %d\n", t);
            // 获取status节点
            status = cJSON_GetObjectItem(qt, "status");
            if (status == NULL)
            {
                printf("cJSON_GetObjectItem err\n");
                return -1;
            }
            printf("status = %d\n", status->valueint);
            // 创建历史数据查询线程
            pthread_t tid;
            // 传递指向时间值的指针
            pthread_create(&tid, NULL, history_thread, NULL);
            // 设置线程为分离状态，避免内存泄漏
            pthread_detach(tid);
        }
        else if (type->valueint == 5) // 切换自动手动模式
        {
            struct msgbuf_mode send_mode;
            // 获取mode节点
            cJSON *mode = cJSON_GetObjectItem(qt, "mode");
            if (mode == NULL)
            {
                printf("cJSON_GetObjectItem err\n");
                return -1;
            }
            // 获取mode节点的值
            send_mode.mode = mode->valueint;
            mode_zd = send_mode.mode;
            printf("send_mode.mode = %d\n", send_mode.mode);
            send_mode.mtype = 1;
            send_mode.N_key = 0;
            send_mode.P_key = 0;
            send_mode.N_val = 0;
            send_mode.P_val = 0;
            if (mode_zd == 1)
            {
                // 获取N_key节点
                cJSON *N_key = cJSON_GetObjectItem(qt, "N_key");
                if (N_key == NULL)
                {
                    printf("cJSON_GetObjectItem err\n");
                    return -1;
                }
                // 获取N_key节点的值
                send_mode.N_key = N_key->valueint;
                printf("send_mode.N_key = %d\n", send_mode.N_key);
                // 获取P_key节点
                cJSON *P_key = cJSON_GetObjectItem(qt, "P_key");
                if (P_key == NULL)
                {
                    printf("cJSON_GetObjectItem err\n");
                    return -1;
                }
                // 获取P_key节点的值
                send_mode.P_key = P_key->valueint;
                printf("send_mode.P_key = %d\n", send_mode.P_key);

                // 获取N_val节点
                cJSON *N_val = cJSON_GetObjectItem(qt, "N_val");
                if (N_val == NULL)
                {
                    printf("cJSON_GetObjectItem err\n");
                    return -1;
                }
                // 获取N_val节点的值
                send_mode.N_val = N_val->valuedouble;
                printf("send_mode.N_val = %f\n", send_mode.N_val);
                // 获取P_val节点
                cJSON *P_val = cJSON_GetObjectItem(qt, "P_val");
                if (P_val == NULL)
                {
                    printf("cJSON_GetObjectItem err\n");
                    return -1;
                }
                // 获取P_val节点的值
                send_mode.P_val = P_val->valuedouble;
                printf("send_mode.P_val = %f\n", send_mode.P_val);
                // 开启变化上报线程
                pthread_t tid;
                pthread_create(&tid, NULL, change_thread, NULL);
                // 设置线程为分离状态，避免内存泄漏
                pthread_detach(tid);
            }
            // 发送send_mode结构体到消息队列
            if (msg_queue_send("topic", &send_mode, sizeof(send_mode), 0) < 0)
            {
                printf("msg_queue_send error\n");
                return -1;
            }
            else
            {
                printf("msg_queue_send success\n");
            }
        }
        // 释放消息结构体占用的内存
        MQTTClient_freeMessage(&message);
        // 释放主题名称占用的内存
        MQTTClient_free(topicName);
        return 1;
    }
}

/**
 * @brief 连接丢失回调函数
 * 当客户端与MQTT服务器的连接丢失时，会调用此函数。
 * @param context 上下文指针，可用于传递额外的数据，这里未使用
 * @param cause 连接丢失的原因描述
 */
void connlost(void *context, char *cause)
{
    // 打印连接丢失提示
    printf("\n连接已丢失\n");
    // 打印连接丢失的原因
    printf("     原因: %s\n", cause);
}

/**
 * @brief 发送消息的函数
 * 该函数用于将指定的消息内容发送到指定的主题。
 * @param client MQTT客户端句柄
 * @param payload 要发送的消息内容
 */

void shm_get()
{
    // 打开文件"data.JSON"以写入读取数据
    FILE *fp = fopen("data.JSON", "w+");
    if (fp == NULL)
    {
        perror("fopen err");
    }

    // 创建root节点
    cJSON *root = cJSON_CreateObject();
    // 在root节点中添加type节点
    cJSON_AddItemToObject(root, "type", cJSON_CreateNumber(1));
    // 在root节点中添加result节点
    cJSON_AddItemToObject(root, "result", cJSON_CreateNumber(node_arr[0].ret));

    // 在root节点中创建stm32节点
    cJSON *stm32 = cJSON_CreateObject();
    cJSON_AddItemToObject(root, "stm32", stm32);
    int i = 0;

    // 在stm32节点中添加data数组
    cJSON *data = cJSON_CreateArray();
    cJSON_AddItemToObject(stm32, "data", data);

    // 在data节点中添加N2节点
    cJSON *N2 = cJSON_CreateObject();
    cJSON_AddItemToArray(data, N2);
    // 在N2节点中添加key节点
    cJSON_AddItemToObject(N2, "key", cJSON_CreateNumber(node_arr[0].key));
    // 在N2节点中添加val节点
    char str[20]; // 足够存储转换后的字符串
    // 使用 sprintf 函数
    sprintf(str, "%.2lf", node_arr[0].new_val.f_val);
    // 在N2节点中添加val节点
    cJSON_AddItemToObject(N2, "val", cJSON_CreateString(str));

    // 判断new_val和old_val是否相等
    if (node_arr[0].new_val.f_val != node_arr[0].old_val.f_val)
    {
        flag = 1;
        node_arr[0].old_val.f_val = node_arr[0].new_val.f_val;
    }

    // 在data节点中添加P节点
    cJSON *P = cJSON_CreateObject();
    cJSON_AddItemToArray(data, P);
    // 在P节点中添加key节点
    cJSON_AddItemToObject(P, "key", cJSON_CreateNumber(node_arr[1].key));
    // 在P节点中添加val节点
    char str1[20]; // 足够存储转换后的字符串
    // 使用 sprintf 函数
    sprintf(str1, "%.2lf", node_arr[1].new_val.f_val);
    cJSON_AddItemToObject(P, "val", cJSON_CreateString(str1));

    // 判断new_val和old_val是否相等
    if (node_arr[1].new_val.f_val != node_arr[1].old_val.f_val)
    {
        flag = 1;
        node_arr[1].old_val.f_val = node_arr[1].new_val.f_val;
    }

    // 在data节点中添加Warner节点
    cJSON *Warner = cJSON_CreateObject();
    cJSON_AddItemToArray(data, Warner);
    // 在Warner节点中添加key节点
    cJSON_AddItemToObject(Warner, "key", cJSON_CreateNumber(node_arr[2].key));
    // 在Warner节点中添加val节点
    char str2[20]; // 足够存储转换后的字符串
    // 使用 sprintf 函数
    sprintf(str2, "%.2lf", node_arr[2].new_val.f_val);
    cJSON_AddItemToObject(Warner, "val", cJSON_CreateString(str2));

    // 判断new_val和old_val是否相等
    if (node_arr[2].new_val.f_val != node_arr[2].old_val.f_val)
    {
        flag = 1;
        node_arr[2].old_val.f_val = node_arr[2].new_val.f_val;
    }

    // 在data节点中添加Mixer节点
    cJSON *Mixer = cJSON_CreateObject();
    cJSON_AddItemToArray(data, Mixer);
    // 在Mixer节点中添加key节点
    cJSON_AddItemToObject(Mixer, "key", cJSON_CreateNumber(node_arr[3].key));
    // 在Mixer节点中添加val节点
    char str3[20]; // 足够存储转换后的字符串
    // 使用 sprintf 函数
    sprintf(str3, "%.2lf", node_arr[3].new_val.f_val);
    cJSON_AddItemToObject(Mixer, "val", cJSON_CreateString(str3));

    // 判断new_val和old_val是否相等
    if (node_arr[3].new_val.f_val != node_arr[3].old_val.f_val)
    {
        flag = 1;
        node_arr[3].old_val.f_val = node_arr[3].new_val.f_val;
    }

    // 在root节点中创建modbus节点
    cJSON *modbus = cJSON_CreateObject();
    cJSON_AddItemToObject(root, "modbus", modbus);
    // 在modbus节点中创建data数组
    cJSON *data1 = cJSON_CreateArray();
    cJSON_AddItemToObject(modbus, "data", data1);

    // 在data1数组中添加PH节点
    cJSON *PH = cJSON_CreateObject();
    cJSON_AddItemToArray(data1, PH);
    // 在PH节点中添加key节点
    cJSON_AddItemToObject(PH, "key", cJSON_CreateNumber(node_arr[4].key));
    // 在PH节点中添加val节点
    char str4[20]; // 足够存储转换后的字符串
    // 使用 sprintf 函数
    sprintf(str4, "%.2lf", node_arr[4].new_val.f_val);
    cJSON_AddItemToObject(PH, "val", cJSON_CreateString(str4));

    // 判断new_val和old_val是否相等
    if (node_arr[4].new_val.f_val != node_arr[4].old_val.f_val)
    {
        flag = 1;
        node_arr[4].old_val.f_val = node_arr[4].new_val.f_val;
    }

    // 在data1数组中添加water节点
    cJSON *water = cJSON_CreateObject();
    cJSON_AddItemToArray(data1, water);
    // 在water节点中添加key节点
    cJSON_AddItemToObject(water, "key", cJSON_CreateNumber(node_arr[5].key));
    // 在water节点中添加val节点
    char str5[20]; // 足够存储转换后的字符串
    // 使用 sprintf 函数
    sprintf(str5, "%.2lf", node_arr[5].new_val.f_val);
    cJSON_AddItemToObject(water, "val", cJSON_CreateString(str5));

    // 判断new_val和old_val是否相等
    if (node_arr[5].new_val.f_val != node_arr[5].old_val.f_val)
    {
        flag = 1;
        node_arr[5].old_val.f_val = node_arr[5].new_val.f_val;
    }

    // 在data1数组中添加CO2节点
    cJSON *CO2 = cJSON_CreateObject();
    cJSON_AddItemToArray(data1, CO2);
    // 在CO2节点中添加key节点
    cJSON_AddItemToObject(CO2, "key", cJSON_CreateNumber(node_arr[6].key));
    // 在CO2节点中添加val节点
    char str6[20]; // 足够存储转换后的字符串
    // 使用 sprintf 函数
    sprintf(str6, "%.2lf", node_arr[6].new_val.f_val);
    cJSON_AddItemToObject(CO2, "val", cJSON_CreateString(str6));

    // 判断new_val和old_val是否相等
    if (node_arr[6].new_val.f_val != node_arr[6].old_val.f_val)
    {
        flag = 1;
        node_arr[6].old_val.f_val = node_arr[6].new_val.f_val;
    }

    // 在data1数组中添加DO节点
    cJSON *DO = cJSON_CreateObject();
    cJSON_AddItemToArray(data1, DO);
    // 在DO节点中添加key节点
    cJSON_AddItemToObject(DO, "key", cJSON_CreateNumber(node_arr[7].key));
    // 在DO节点中添加val节点
    char str7[20]; // 足够存储转换后的字符串
    // 使用 sprintf 函数
    sprintf(str7, "%.2lf", node_arr[7].new_val.f_val);
    cJSON_AddItemToObject(DO, "val", cJSON_CreateString(str7));

    // 判断new_val和old_val是否相等
    if (node_arr[7].new_val.f_val != node_arr[7].old_val.f_val)
    {
        flag = 1;
        node_arr[7].old_val.f_val = node_arr[7].new_val.f_val;
    }

    // 在data1数组中添加valve节点
    cJSON *valve = cJSON_CreateObject();
    cJSON_AddItemToArray(data1, valve);
    // 在valve节点中添加key节点
    cJSON_AddItemToObject(valve, "key", cJSON_CreateNumber(node_arr[8].key));
    // 在valve节点中添加val节点
    char str8[20]; // 足够存储转换后的字符串
    // 使用 sprintf 函数
    sprintf(str8, "%.2lf", node_arr[8].new_val.f_val);
    cJSON_AddItemToObject(valve, "val", cJSON_CreateString(str8));

    // 判断new_val和old_val是否相等
    if (node_arr[8].new_val.f_val != node_arr[8].old_val.f_val)
    {
        flag = 1;
        node_arr[8].old_val.f_val = node_arr[8].new_val.f_val;
    }

    // 在data1数组中添加detergent节点
    cJSON *detergent = cJSON_CreateObject();
    cJSON_AddItemToArray(data1, detergent);
    // 在detergent节点中添加key节点
    cJSON_AddItemToObject(detergent, "key", cJSON_CreateNumber(node_arr[9].key));
    // 在detergent节点中添加val节点
    char str9[20]; // 足够存储转换后的字符串
    // 使用 sprintf 函数
    sprintf(str9, "%.2lf", node_arr[9].new_val.f_val);
    cJSON_AddItemToObject(detergent, "val", cJSON_CreateString(str9));

    // 判断new_val和old_val是否相等
    if (node_arr[9].new_val.f_val != node_arr[9].old_val.f_val)
    {
        flag = 1;
        node_arr[9].old_val.f_val = node_arr[9].new_val.f_val;
    }

    char *json_str = cJSON_Print(root);
    // 将JSON字符串写入文件
    fwrite(json_str, 1, strlen(json_str), fp);

    // 读取文件内容到input
    fseek(fp, 0, SEEK_SET);
    fread(input, 1, sizeof(input), fp);

    // 释放字符串
    free(json_str);
    // 释放root节点
    cJSON_Delete(root);
    // 关闭文件
    fclose(fp);
}

void JSON_config()
{
    // 从config.json文件中读取JSON数据
    FILE *fp = fopen("config.json", "r");
    if (fp == NULL)
    {
        printf("无法打开文件\n");
        return;
    }
    // 读取文件内容到字符串
    fseek(fp, 0, SEEK_END);
    long fsize = ftell(fp);
    fseek(fp, 0, SEEK_SET);
    char *json_str = (char *)malloc(fsize + 1);
    if (!json_str)
    {
        printf("内存分配失败\n");
        fclose(fp);
        return;
    }
    fread(json_str, 1, fsize, fp);
    fclose(fp);
    json_str[fsize] = '\0'; // 添加字符串结束符
    // 解析JSON数据
    cJSON *root = cJSON_Parse(json_str);
    if (root == NULL)
    {
        printf("解析JSON数据失败\n");
        free(json_str);
        return;
    }
    // 获取节点数组
    // cJSON *stm32 = cJSON_GetObjectItem(root, "stm32");
    // cJSON *data = cJSON_GetObjectItem(stm32, "data");
    // //获取modbus节点个数
    //   cJSON *modbus = cJSON_GetObjectItem(root, "modbus");
    // cJSON *data1 = cJSON_GetObjectItem(modbus, "data");
    // 获取两个节点总和

    // 打印三个节点个数

    // 遍历节点数组
    // int arr_size = cJSON_GetArraySize(data);
    // stm32_arr = (struct std_node *)malloc(arr_size * sizeof(struct std_node));

    // for (int i = 0; i < arr_size; i++)
    // {
    //     cJSON *item = cJSON_GetArrayItem(data, i);
    //     stm32_arr[i].key = cJSON_GetObjectItem(item, "key")->valueint;
    //     stm32_arr[i].type = cJSON_GetObjectItem(item, "type")->valueint;
    // }

    // 解析出mqtt_server的addr和port
    cJSON *mqtt_server = cJSON_GetObjectItem(root, "mqtt_server");
    strcpy(IP, cJSON_GetObjectItem(mqtt_server, "addr")->valuestring);
    // 在IP后面添加\0
    for (int i = 0; i < strlen(IP); i++)
    {
        if (IP[i] == ',')
        {
            IP[i] = '\0';
            break;
        }
    }

    strcat(ADDRESS, IP);
    strcat(ADDRESS, ":");
    strcat(ADDRESS, "1883");
    printf("ADDRESS = %s\n", ADDRESS);
    // 释放内存
    cJSON_Delete(root);
    free(json_str);
}

int main(int argc, char *argv[])
{
    JSON_config();

    // 创建sqlite3数据库
    int rc1 = sqlite3_open("./gateWay.db", &db);
    if (rc1 != SQLITE_OK)
    {
        fprintf(stderr, "无法打开数据库: %s\n", sqlite3_errmsg(db));
        return 1;
    }
    else
    {
        printf("打开数据库成功\n");
    }
    // 创建data表,存放时间戳和data数据
    char *errmsg;
    char *sql = "CREATE TABLE IF NOT EXISTS data (timestamp TEXT, data TEXT);";
    rc1 = sqlite3_exec(db, sql, NULL, 0, &errmsg);
    if (rc1 != SQLITE_OK)
    {
        fprintf(stderr, "创建表失败: %s\n", errmsg);
    }
    else
    {
        printf("创建表成功\n");
    }

    int ret = -1;
    // 初始化共享内存
    ret = shm_init(&para, "shm_test", 1024);
    if (ret < 0)
    {
        return -1;
    }
    // 获取共享内存地址
    void *node_p = shm_getaddr(&para);
    if (node_p == NULL)
    {
        return -1;
    }

    // 前4个字节存储实际的设备数目
    total = (int *)node_p;
    // 后面空间存储数据点
    node_arr = (struct std_node *)(node_p + sizeof(int));

    printf("num = %d\n", *total);

    // 定义MQTT连接选项结构体，并初始化为默认值
    MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
    int rc;

    // 创建MQTT客户端实例，指定服务器地址和客户端ID
    MQTTClient_create(&client, ADDRESS, CLIENTID,
                      MQTTCLIENT_PERSISTENCE_NONE, NULL);

    // 初始化连接选项
    // 设置保持连接的时间间隔，单位为秒
    conn_opts.keepAliveInterval = 20;
    // 设置是否清除会话信息
    conn_opts.cleansession = 1;

    // 设置MQTT客户端的回调函数
    // 分别为连接丢失回调、消息到达回调、消息发送确认回调
    MQTTClient_setCallbacks(client, NULL, connlost, msgarrvd, delivered);

    // 连接到MQTT服务器
    if ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS)
    {
        // 若连接失败，打印错误信息并退出程序
        printf("连接失败，返回码 %d\n", rc);
        exit(EXIT_FAILURE);
    }
    // 打印订阅主题的提示信息
    printf("正在订阅主题 %s\n客户端ID为 %s，使用QoS等级 %d\n\n",
           TOPIC_DOWN, CLIENTID, QOS);
    // 订阅指定主题，并指定服务质量等级
    MQTTClient_subscribe(client, TOPIC_DOWN, QOS);

    // 循环接收用户输入并发送消息
    while (1)
    {
        // 从共享内存中获取设备数据
        shm_get();
        sleep(1);
    }
    // 取消订阅指定主题
    MQTTClient_unsubscribe(client, TOPIC_DOWN);
    // 断开与MQTT服务器的连接
    MQTTClient_disconnect(client, 10000);
    // 销毁MQTT客户端实例
    MQTTClient_destroy(&client);
    return rc;
}